using System;
using System.Collections;
using System.Windows.Markup;

namespace Common.Core.Configuration
{
	//
	// MarkupExtension that is base for an extension that creates
	// Collection<T>, List<T>, or Dictionary<T>.
	// (CollectionType is either IList or IDictionary).
	public abstract class CollectionOfTExtensionBase<CollectionType> : MarkupExtension
		where CollectionType : class
	{
		// Default the collection to typeof(Object)
		protected CollectionOfTExtensionBase() : this( typeof(Object) )
		{}

		protected CollectionOfTExtensionBase( Type typeArgument )
		{
			_typeArgument = typeArgument;
		}

		// Items is the actual collection we'll return from ProvideValue.
		public CollectionType Items
		{
			get
			{
				if ( _items == null )
				{
					var collectionType = GetCollectionType( TypeArgument );
					_items = Activator.CreateInstance( collectionType ) as CollectionType;
				}
				return _items;
			}
		}	CollectionType _items;


		// TypeArgument is the "T" in e.g. Collection<T>
		public Type TypeArgument
		{
			get { return _typeArgument; }
			set
			{
				_typeArgument = value;

				// If the TypeArgument doesn't get set until after
				// items have been added, we need to re-create items
				// to be the right type.
				if ( _items != null )
				{
					object oldItems = _items;
					_items = null;
					CopyItems( oldItems );
				}
			}
		}	Type _typeArgument;
		

		// Default implementation of CopyItems that works for Collection/List
		// (but not Dictionary).
		protected virtual void CopyItems( object oldItems )

		{
			var oldItemsAsList = oldItems as IList;
			var newItemsAsList = Items as IList;
			if ( oldItemsAsList != null )
			{
				for ( var i = 0; i < oldItemsAsList.Count; i++ )
				{
					if ( newItemsAsList != null )
					{
						newItemsAsList.Add( oldItemsAsList[ i ] );
					}
				}
			}
		}

		// Get the generic type, e.g. typeof(Collection<>), aka Collection`1.
		protected abstract Type GetCollectionType( Type typeArgument );

		// Provide the collection instance.
		public override object ProvideValue( IServiceProvider serviceProvider )
		{
			return _items;
		}
	}
}